/*
 * Mat3.cpp
 *
 *  Created on: 20.09.2009
 *      Author: christoph
 */

// this file is included by its header file to satisfy the compiler

template <typename Real>
Mat3<Real>::Mat3() {
	for ( int i = 0; i < 9; i++ ) {
		data[i] = 0;
	}
}

template <typename Real>
Mat3<Real>::Mat3(	const Real r0, const Real r1, const Real r2,
					const Real r3, const Real r4, const Real r5,
					const Real r6, const Real r7, const Real r8 ) {
	this->data[0] = r0;
	this->data[1] = r1;
	this->data[2] = r2;

	this->data[3] = r3;
	this->data[4] = r4;
	this->data[5] = r5;

	this->data[6] = r6;
	this->data[7] = r7;
	this->data[8] = r8;
}

template <typename Real>
Mat3<Real>::Mat3( const Real matrix[9] ) {
	for ( int i = 0; i < 9; i++ ) {
		this->data[i] = matrix[i];
	}
}

template <typename Real>
Mat3<Real>::Mat3( const Mat3& m2 ) {
	for ( int i = 0; i < 9; i++ ) {
		this->data[i] = m2.data[i];
	}
}

template <typename Real>
Mat3<Real>::~Mat3() {
}

template <typename Real>
const Real* Mat3<Real>::operator [] ( int iRow ) const {
	return &data[iRow*3];
}

template <typename Real>
Real* Mat3<Real>::operator [] ( int iRow ) {
	return &data[iRow*3];
}

template <typename Real>
Real Mat3<Real>::operator () ( int iRow, int iCol ) const {
	return data[iRow*3+iCol];
}

template <typename Real>
Real& Mat3<Real>::operator () ( int iRow, int iCol ) {
	return data[iRow*3+iCol];
}

template <typename Real>
void Mat3<Real>::setRow( int iRow, const Vec3<Real>& v2Val ) {
	data[iRow*3 + 0] = v2Val.data[0];
	data[iRow*3 + 1] = v2Val.data[1];
	data[iRow*3 + 2] = v2Val.data[2];
}

template <typename Real>
void Mat3<Real>::setCol( int iCol, const Vec3<Real>& v2Val ) {
	data[0*3 + iCol] = v2Val.data[0];
	data[1*3 + iCol] = v2Val.data[1];
	data[2*3 + iCol] = v2Val.data[2];
}

template <typename Real>
Vec3<Real> Mat3<Real>::getRow( int iRow ) const {
	return Vec3<Real>( data[iRow*3 + 0], data[iRow*3 + 1], data[iRow*3 + 2] );
}

template <typename Real>
Vec3<Real> Mat3<Real>::getCol( int iCol ) const {
	return Vec3<Real>( data[0*3 + iCol], data[1*3 + iCol], data[2*3 + iCol] );
}

template <typename Real>
void Mat3<Real>::setZero() {
	for ( int i = 0; i < 9; i++ ) {
		data[i] = 0;
	}
}

template <typename Real>
void Mat3<Real>::setIdentity() {
	data[0] = 1;
	data[1] = 0;
	data[2] = 0;

	data[3] = 0;
	data[4] = 1;
	data[5] = 0;

	data[6] = 0;
	data[7] = 0;
	data[8] = 1;
}

template <typename Real>
Mat3<Real>& Mat3<Real>::operator = ( const Mat3<Real>& m2Rhs ) {
	for ( int i = 0; i < 9; i++ ) {
		data[i] = m2Rhs.data[i];
	}
}

// arithmetic operations
template <typename Real>
Mat3<Real> Mat3<Real>::operator + ( const Mat3<Real>& mRhs ) const {
	return Mat3<Real>( 	data[0] + mRhs.data[0], data[1] + mRhs.data[1], data[2] + mRhs.data[2],
						data[3] + mRhs.data[3], data[4] + mRhs.data[4], data[5] + mRhs.data[5],
						data[6] + mRhs.data[6], data[7] + mRhs.data[7], data[8] + mRhs.data[8] );
}

template <typename Real>
Mat3<Real> Mat3<Real>::operator - ( const Mat3<Real>& mRhs ) const {
	return Mat3<Real>( 	data[0] - mRhs.data[0], data[1] - mRhs.data[1], data[2] - mRhs.data[2],
						data[3] - mRhs.data[3], data[4] - mRhs.data[4], data[5] - mRhs.data[5],
						data[6] - mRhs.data[6], data[7] - mRhs.data[7], data[8] - mRhs.data[8] );
}

template <typename Real>
Mat3<Real> Mat3<Real>::operator * ( const Real rRhs ) const {
	return Mat3<Real>(	data[0] * rRhs, data[1] * rRhs, data[2] * rRhs,
						data[3] * rRhs, data[4] * rRhs, data[5] * rRhs,
						data[6] * rRhs, data[7] * rRhs, data[8] * rRhs );
}

template <typename Real>
Mat3<Real> Mat3<Real>::operator / ( const Real rRhs ) const {
	return Mat3<Real>(	data[0] / rRhs, data[1] / rRhs, data[2] / rRhs,
						data[3] / rRhs, data[4] / rRhs, data[5] / rRhs,
						data[6] / rRhs, data[7] / rRhs, data[8] / rRhs );
}


template <typename Real>
Mat3<Real> Mat3<Real>::operator += ( const Mat3<Real>& mRhs ) {
	for ( int i = 0; i < 9; i++ ) {
		data[i] += mRhs.data[i];
	}
}

template <typename Real>
Mat3<Real> Mat3<Real>::operator -= ( const Mat3<Real>& mRhs ) {
	for ( int i = 0; i < 9; i++ ) {
		data[i] -= mRhs.data[i];
	}
}

template <typename Real>
Mat3<Real> Mat3<Real>::operator *= ( const Real rRhs ) {
	for ( int i = 0; i < 9; i++ ) {
		data[i] *= rRhs;
	}
}

template <typename Real>
Mat3<Real> Mat3<Real>::operator /= ( const Real rRhs ) {
	for ( int i = 0; i < 9; i++ ) {
		data[i] /= rRhs;
	}
}

// TODO comparison operations
template <typename Real>
bool Mat3<Real>::operator == ( const Mat3<Real>& m2Rhs ) const {
	return 	data[0] == m2Rhs.data[0] && data[1] == m2Rhs.data[2] && data[2] == m2Rhs.data[2] &&
			data[3] == m2Rhs.data[3] && data[4] == m2Rhs.data[4] && data[5] == m2Rhs.data[5] &&
			data[6] == m2Rhs.data[6] && data[7] == m2Rhs.data[7] && data[8] == m2Rhs.data[8];
}

template <typename Real>
bool Mat3<Real>::operator != ( const Mat3<Real>& m2Rhs ) const {
	return 	data[0] != m2Rhs.data[0] || data[1] != m2Rhs.data[1] || data[2] != m2Rhs.data[2] ||
			data[3] != m2Rhs.data[3] || data[4] != m2Rhs.data[4] || data[5] != m2Rhs.data[5] ||
			data[6] != m2Rhs.data[6] || data[7] != m2Rhs.data[7] || data[8] != m2Rhs.data[8];
}

// TODO geometric operations

template <typename Real>
Vec3<Real> Mat3<Real>::operator * ( const Vec3<Real>& v3Rhs ) const {
	return Vec3<Real>( 	data[0] * v3Rhs[0] + data[3] * v3Rhs[1] + data[6] * v3Rhs[2],
						data[1] * v3Rhs[0] + data[4] * v3Rhs[1] + data[7] * v3Rhs[2],
						data[2] * v3Rhs[0] + data[5] * v3Rhs[1] + data[8] * v3Rhs[2] );
}

// other
template <typename Real>
Mat3<Real> Mat3<Real>::transpose() const {
	return Mat3<Real>(	data[0], data[3], data[6],
						data[1], data[4], data[7],
						data[2], data[5], data[8] );
}

template <typename Real>
Mat3<Real> Mat3<Real>::inverse() const {
	// TODO implement inverse
	return Mat3<Real>();
}

template <typename Real>
Mat3<Real> Mat3<Real>::adjoint() const {
	// TODO implement adjoint
	return Mat3<Real>();
}

template <typename Real>
Real Mat3<Real>::determinant() const {
	// TODO implement determinant
	return Mat3<Real>();

}
